//============================================================================
// Name        : Stratus.cpp
// Author      : Yu-shian Chen
// Version     :
// Copyright   : Your copyright notice
// Description : Hello World in C, Ansi-style
//============================================================================

#include <stdlib.h>
#include <cstring>
#include <io.h>
#include <sys/stat.h>
//#include <libxml++/libxml++.h>
#include <sys/types.h>
#include <dirent.h>
#include <errno.h>
#include <vector>
#include <queue>
#include <list>

#ifdef WINDOWS
#include <direct.h>
#define GetCurrentDir _getcwd
#else
#include <unistd.h>
#define GetCurrentDir getcwd
#endif

#include <iostream>
#include <stdio.h>
#include "stratus.h"

using namespace std;

void listAll(char* dir, int depth) {
	// Get the current directory so we can return to it
	char returnedWorkPath[_MAX_PATH];
	GetCurrentDir(returnedWorkPath, _MAX_PATH);
	/* Change to the explored directory */
	chdir(dir);
	struct stat traversed_entry_stat;
	_finddata_t traversedEntry;

	// This will grab the first file in the directory
	// "*" can be changed if you only want to look for specific sub_directories
	intptr_t handle = _findfirst("*", &traversedEntry);
	int filedes;
	if (handle == -1) { // No sub_directories or directories found
		perror("Error searching for file");
		exit(1);
	}
	do {
		/* Get the entry stat by stat() from stat.h*/
		if (fstat(filedes, &traversed_entry_stat) < 0) {
			fprintf(stderr, "stat error");
		}

		if (strcmp(traversedEntry.name, ".") == 0
				|| strcmp(traversedEntry.name, "..") == 0
				|| (traversedEntry.attrib & _A_HIDDEN))
			continue;
		if (traversedEntry.attrib & _A_SUBDIR) { // Use bitmask to see if this is a directory

			cout << "Path: " << dir << ", Directory: " << traversedEntry.name
					<< endl;
			if (depth > 0)
				listAll(traversedEntry.name, depth - 1);
		}
		if (S_ISREG(traversed_entry_stat.st_mode)) {
			int current_file_size = traversed_entry_stat.st_size;
			cout << "Path: " << dir << ", File: " << traversedEntry.name
					<< " of size " << current_file_size << ". " << endl;
		}

	} while (_findnext(handle, &traversedEntry) == 0);

	_findclose(handle); // Close the stream
	chdir(returnedWorkPath);
}

/* The input is an already known directory name. */
int getSubEntry(char* dir, vector<string> &sub_dirs, vector<string> &sub_fles) {
	// Get the current directory so we can return to it
	char returnedWorkPath[_MAX_PATH];
	GetCurrentDir(returnedWorkPath, _MAX_PATH);

	/* Change to the explored directory */
	chdir(dir);
	// add a secure check of input here
	DIR * dp;
	struct dirent *direntry_pointer;
	struct stat current_entry_stat;

	if ((dp = opendir(dir)) == NULL) {
		cout << "Error(" << errno << ") opening " << dir << endl;
		return errno;
	}
	while ((direntry_pointer = readdir(dp)) != NULL) {
		char* current_entry_name = direntry_pointer->d_name;

		/* filter "." and ".." links */
		if (strcmp(current_entry_name, ".") == 0
				|| strcmp(current_entry_name, "..") == 0)
			continue;
		int error_stat = stat(current_entry_name, &current_entry_stat);
		if (error_stat < 0) {
			cerr << "stat error:" << error_stat << endl;
		} else {

			if (S_ISREG(current_entry_stat.st_mode)) {
				sub_fles.push_back(string(current_entry_name));
				int current_file_size = current_entry_stat.st_size;
				cout << current_entry_name << " is regular file of size "
						<< current_file_size << " bytes.\n";

			} else if (S_ISDIR(current_entry_stat.st_mode)) {
				sub_dirs.push_back(string(current_entry_name));
				cout << current_entry_name << " is directory.\n ";
			}
		}

	}
	closedir(dp);
	chdir(returnedWorkPath);
	return 0;
}
int getDescentEntry(char* top_folder_path, vector<string> &descent_dirs,
		vector<string> &descent_fles, unsigned int depth) {

	// Get the current directory so we can return to it
	char returnedWorkPath[_MAX_PATH];
	GetCurrentDir(returnedWorkPath, _MAX_PATH);

	/*set up the depth */
	unsigned int current_depth = depth;

	/* Change to the explored directory */
	chdir(top_folder_path);

	list<string> route = list<string>(top_folder_path);
//	route.push_back(top_folder_path);

	queue<string> dir_to_traversed = queue<string>();
	dir_to_traversed.push(top_folder_path);

	/* Breadth first traversal */
	while (current_depth >= 0 && dir_to_traversed.size() > 0) {
		vector<string> sub_directories = vector<string>();
		vector<string> sub_files = vector<string>();

		getSubEntry((char*) dir_to_traversed.front(), sub_directories,
				sub_files);
		dir_to_traversed.pop();

		for (unsigned int i = 0; i < sub_directories.size(); i++) {
			string fullpath = top_folder_path;
			fullpath.append(sub_directories[i]);
			dir_to_traversed.push(fullpath);
		}

		for (unsigned int i = 0; i < sub_files.size(); i++) {
			string fullpath = top_folder_path;
			fullpath.append(sub_files[i]);
			descent_fles.push_back(fullpath);
		}
		sub_directories.clear();
		sub_files.clear();
		current_depth--;
	}

//	sub_directories
//	sub_files
	chdir(returnedWorkPath);
	return 0;
}

int main(int argc, char *argv[]) {
	puts("!!!Hallow Word!!!");
	char* currentEntry = (char*) ".";
	int traversedDepth = 0;
	if (argv[1]) {
		currentEntry = (argv[1]);
		if (argv[2])
			traversedDepth = atoi(argv[2]);
	}

	if (chdir(currentEntry)) {
		switch (errno) {
		case ENOENT:
			printf("Unable to locate the directory: %s\n", argv[1]);
			break;
		case EINVAL:
			printf("Invalid buffer.\n");
			break;
		default:
			printf("Unknown error.\n");
			break;
		}
	}
	vector<string> descent_directories = vector<string>();
	vector<string> descent_files = vector<string>();

	vector<string> sub_directories = vector<string>();
	vector<string> sub_files = vector<string>();

	getSubEntry(currentEntry, sub_directories, sub_files);

	cout << " == subdirectories:  " << endl;
	for (unsigned int i = 0; i < sub_directories.size(); i++) {
		cout << sub_directories[i] << endl;
	}
	for (unsigned int i = 0; i < sub_files.size(); i++) {
		cout << sub_files[i] << endl;
	}

	return EXIT_SUCCESS;
}

